accessibility
Macromedia Logo Upper Navigation Bar
  Help
Lower Navigation Bar
ProductsSupportDesigner DeveloperDownloadsStoreInternationalSite MapCompany
ColdFusion MX: Using Application Scope to improve COM Performance
TechNote 22921
 

Creating COM objects in Macromedia ColdFusion MX can be significantly slower than in Macromedia ColdFusion 5. This TechNote explains how you can improve COM performance through using the Application scope among all ColdFusion pages.

The Java call to create a new COM object instance can take substantial time. As a result, creating COM objects in ColdFusion MX can be significantly slower than in ColdFusion 5. For example, on some systems, creating a Microsoft Word application object can take more than one second using ColdFusion MX, while on the same system, the overhead of creating the Word object in ColdFusion 5 might be about 200 milliseconds.

WorkAround
In ColdFusion MX, you can improve COM performance substantially if you can share one COM object in the Application scope among all ColdFusion pages.

Use this technique only if the following are true:

The COM object does not need to be created for every request or session. (For session-specific objects, consider using the technique described in this TechNote with the Session scope in place of the Application scope.)
The COM object is designed for sharing.

Because the object can be accessed from multiple pages and sessions simultaneously, you must also consider the following threading and locking issues:

For best performance, the object should be multi-threaded. Otherwise, only one request can access the object at a time.
Lock the code that accesses and modifies common data. In general, you do not have to lock code that modifies a shared object's data, including writable properties or file contents, if the data (as opposed to the object) is not shared by multiple requests. However, specific locking needs depend on the COM object's semantics, interface, and implementation.
All cflock tags in the application that use an Application scope lock share one lock. Therefore, code that accesses a frequently-used COM object inside an Application scope lock can become a bottleneck and reduce throughput if many users request pages that use the object.

Note: You can also improve performance of some COM objects by creating Java stubs, as described in TechNote 22922: Accessing Complex COM Objects using Java Stubs.

Using a Java stub does not improve performance as much as sharing the COM object, but the technique works with all COM objects. To correctly access complex COM objects that do not properly make all their features available through the COM IDispatcher interface, you must generate Java stubs. Therefore, to get the greatest performance increase and prevent possible problems, use both techniques.

Example 1: Using the FileSystem object

The following example uses the Microsoft FileSystem Scripting object in the Application scope. This code creates a user-defined function that returns a structure consisting of the drive letters and free disk space for all hard drives on the system.

<cfapplication name="comtest" clientmanagement="No" Sessionmanagement="yes">

<!--- Uncomment the following line if you must delete the object from the Application scope during debugging. Then restore the comments. 
		This technique is faster than stopping and starting the ColdFusion server. --->
 <!--- <cfset structdelete(Application, "fso")> --->

<!--- The getFixedDriveSpace user-defined function returns a structure with the drive letters as keys
		and the drive's free space as data for all fixed drives on a system. 
		The function does not take any arguments --->

<cffunction name="getFixedDriveSpace" returnType="struct" output=True>
	<!--- If the FileSystemObject does not exist in the Application scope, create it. --->
	<!--- For information on the use of initialization variables and locking in this code, see 
			“Locking Application variables efficiently” in Chapter 15, “Using Persistent Data and Locking”
			of Developing ColdFusion MX Applications with CFML. --->
	<cfset fso_is_initialized = False>
	<cflock scope="application" type="readonly" timeout="12">
		<cfset fso_is_initialized = StructKeyExists(Application, "fso")>
	</cflock>
	<cfif not fso_is_initialized >
		<cflock scope="Application" type="EXCLUSIVE" timeout="12">
			<cfif NOT StructKeyExists(Application, "fso")>
				<CFOBJECT TYPE="COM" ACTION="create" CLASS="Scripting.FileSystemObject"
					NAME="Application.fso" server="\\localhost">
			</cfif>
		</cflock>
	</cfif>

	<!--- Get the drives collection and loop through it to populate the structure. --->
	<cfset drives=Application.fso.drives()>
	<cfset driveSpace=StructNew()>
	<cfloop collection="#drives#" item="curDrive">
		<!--- A DriveType of 2 indicates a fixed disk --->
		<cfif curDrive.DriveType IS 2>
		<!--- Use dynamic array notation with the drive letter for the struct key --->
			<cfset driveSpace["#curDrive.DriveLetter#"]=curDrive.availablespace>
		</cfif>
	</cfloop>
	<cfreturn driveSpace>
</cffunction>

<!--- Test the function. Get the execution time for running the function --->
<cfset start = getTickCount()>
<cfset DriveInfo=getFixedDriveSpace()>
<cfoutput>Execution Time: #int(getTickCount()-start)# milliseconds</cfoutput><br>
Results: <br>
<cfdump var="#driveInfo#">

Example 2: Using the Microsoft Word application object

The following example uses the Microsoft Word application COM object in the Application scope to convert a word document to HTML. This example works with Word 97 as written. To work with Word 2000, change the "Val(10)" to "Val(8). This example uses an Application scope lock to ensure that no other page interrupts processing of the file.

<cfapplication name="comtest" clientmanagement="No" Sessionmanagement="yes">
<!--- Uncomment the following line if you need to delete the object from the Application scope --->
<!---  <cfset structdelete(Application, "MyWordObj")> --->

<!--- use the GetTickCount function to get a current time indicator, used for displaying
      the total processing time. --->
<cfset start = GetTickCount()>
<!--- If necessary, create the Word.application obeject and put it in the application scope --->
<cfset WordObj_is_initialized = False>
<cflock scope="application" type="readonly" timeout=12>
	<cfset WordObj_is_initialized = StructKeyExists(application, "MyWordObj")>
</cflock>
<cfif not WordObj_is_initialized >
	<cflock scope="Application" type="exclusive" timeout="12">
		<cfif not StructKeyExists(application, "MyWordObj")>

<!--- First try to connect to an existing Word object --->
			<cftry>
			In try. <br>
				<cfobject type="com"
					action="connect"
					class="Word.application"
					name="Application.MyWordobj"
					context="local"> 
				<cfcatch>
				In catch <br>
<!--- There is no existing object, create one --->
					<cfobject type="com"
						action="Create"
						class="Word.application"
						name="Application.MyWordobj"
						context="local"> 
				</cfcatch>
			</cftry>
			<cfset Application.mywordobj.visible = False>
		</cfif>
	</cflock>
</cfif>

<!--- convert a word document in temp.doc to an html file in temp.htm --->
<!--- Because this example uses a fixed file name, multiple pages might try to use the file
		simultaneously. The lock ensures that all actions from reading the input file through 
		closing the output file are a single "atomic" operation, and the next page cannot access 
		the file until the current page completes all processing. 
	Use a named lock instead of the Application scope lock to reduce lock contention. --->
<cflock name="WordObjLock" type="exclusive" timeout="12">
	<cfset docs = application.mywordobj.documents()>
	<cfset docs.open("c:\CFusionMX\wwwroot\temp.doc")>
	<cfset converteddoc = application.mywordobj.activedocument>
	<!--- Val(10) works with Word 97. Use Val(8) for Word 2000 --->
	<cfset converteddoc.saveas("c:\CFusionMX\wwwroot\temp.htm",val(10))>
	<cfset converteddoc.close()>
</cflock>

<cfoutput>
	Conversion of temp.htm Complete<br>
	Execution Time: #int(getTickCount()-start)# milliseconds<br>
</cfoutput>
Note: Your code must do all necessary cleanup. For example, if your COM object (such as Word) is in a separate process, you must clean up the processes that are no longer needed. For example, the following code quits Word and deletes the MyWordObj from the Application scope. This issue is particularly important during development, where you might end up with multiple copies of a process running.
<cfif StructKeyExists(Application, "MyWordobj")> 
    <cfset Application.MyWordobj.quit()> 
    <cfset structdelete(Application, "MyWordObj")>
</cfif>    

Related TechNotes:

Accessing Complex COM Objects using Java Stubs (TechNote 22922)


       
Products:     ColdFusion
Browser:     N/A
Server:     N/A
Platform:     N/A
OS:     Windows 2000
   Windows 98
   Windows NT 4.0
   Windows XP
Database:     N/A

How useful was this document?
less more

1

2

3

4

5

How can the document be improved? (300 characters or less - you will not receive a reply.)


Icon or Spacer ©1995-2002 Macromedia, Inc. All rights reserved.
Use of this website signifies your agreement to the Terms of Use.
Privacy | Site Map
| Contact us | Accessibility